package com.sx.mvvmlibs.base

import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.CallSuper
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.viewbinding.ViewBinding
import com.blankj.utilcode.util.ThreadUtils
import com.gyf.immersionbar.ImmersionBar
import com.lxj.xpopup.core.BasePopupView
import com.sx.mvvmlibs.app.ContainerActivity
import com.sx.mvvmlibs.base.impl.ILoadingDialog
import com.sx.mvvmlibs.base.impl.IView
import com.sx.mvvmlibs.view.CustomLoadingDialog
import org.koin.android.ext.android.inject
import org.koin.core.qualifier.named
import java.util.concurrent.ConcurrentHashMap

/**
 * @Author: YY
 * @Date: 2022/1/8
 * @Describe: ViewBinding 基类Activity
 */
abstract class ViewBindingBaseActivity<V : ViewBinding, VM : BaseViewModel<out BaseModel>> :
    AppCompatActivity(), IView<V, VM>, ILoadingDialog {

    protected lateinit var mBinding: V

    protected lateinit var mViewModel: VM

    val mPopMap: ConcurrentHashMap<Int, BasePopupView> by inject(named("pop_map"))

    // 保证只有主线程访问这个变量，所以 lazy 不需要同步机制
    private val mLoadingDialog by lazy(mode = LazyThreadSafetyMode.NONE) {
        CustomLoadingDialog(this, loadingDialogLayout())
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 初始化状态栏
        initStatusBar()
        mBinding = initBinding(layoutInflater, null)
        initContentView(mBinding.root)
        // 初始化ViewModel
        initViewModel()
        // 初始化界面传递参数
        initParam()
        // 初始化监听
        initListener()
        // 初始化通用的 UI 事件
        initUIChangeLiveData()
        // 初始化界面观察者的监听
        initViewObservable()
        // 初始化数据
        initData()
        // 初始化数据
        initData(savedInstanceState)
    }

    abstract override fun initBinding(inflater: LayoutInflater, container: ViewGroup?): V

    open fun initStatusBar() {
        ImmersionBar.with(this)
            .fitsSystemWindows(true)
            .statusBarDarkFont(true).init()
    }

    open fun initContentView(contentView: View) {
        setContentView(contentView)
    }

    @CallSuper
    override fun initViewModel() {
        mViewModel = createViewModel(this)
        // 让 vm 可以感知 v 的生命周期
        lifecycle.addObserver(mViewModel)
        // 注册RxBus
        mViewModel.registerRxBus()
    }


    @CallSuper
    override fun initUIChangeLiveData() {

        // 启动Activity
        observe(mViewModel.mUI.initStartActivityEvent()) {
            val clz: (Class<*>) = it?.get(BaseViewModel.ParameterField.CLASS) as (Class<*>)
            val bundle: Bundle? = it[BaseViewModel.ParameterField.BUNDLE] as Bundle?
            startActivity(clz, bundle)
        }

        // 启动并结束上一个Activity
        observe(mViewModel.mUI.initStartActivityFinishEvent()) {
            val clz: (Class<*>) = it?.get(BaseViewModel.ParameterField.CLASS) as (Class<*>)
            val bundle: Bundle? = it[BaseViewModel.ParameterField.BUNDLE] as Bundle?
            startActivityFinish(clz, bundle)
        }

        // 启动盛装的Activity
        observe(mViewModel.mUI.initStartContainerFragmentEvent()) {
            val canonicalName = it!![BaseViewModel.ParameterField.CANONICAL_NAME] as String
            val bundle = it[BaseViewModel.ParameterField.BUNDLE] as Bundle
            startContainerActivity(canonicalName, bundle)
        }

        // 结束Activity
        observe(mViewModel.mUI.initFinishEvent()) {
            finish()
        }

        // 加载弹框
        if (isNeedLoadingDialog()) {
            // 显示加载框
            observe(mViewModel.mUI.getLoadingDialogEvent()) {

                showLoadingDialog(mLoadingDialog, it)
            }
            // 隐藏加载框
            observe(mViewModel.mUI.getDismissDialogEvent()) {
                dismissLoadingDialog(mLoadingDialog)
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        // 界面销毁时移除 vm 的生命周期感知
        if (this::mViewModel.isInitialized) {
            mViewModel.removeRxBus()
            lifecycle.removeObserver(mViewModel)
        }
    }

    /**
     * 原始写法
     * mViewModel.liveData.observe(this, Observer { })
     *
     * 用这个方法可以这么写
     * observe(mViewModel.liveData) { }
     *
     * 或者这么写
     * observe(mViewModel.liveData, this::onChanged)
     *     private fun onChanged(s: String) { }
     */
    fun <T> observe(liveData: LiveData<T>, onChanged: ((t: T) -> Unit)) =
        liveData.observe(this, Observer { onChanged(it) })

    /**
     * 跳转页面
     * @param clz 所跳转的目的Activity类
     */
    open fun startActivity(clz: Class<*>?) {
        startActivity(Intent(this, clz))
    }

    /**
     * 跳转页面
     * @param clz    所跳转的目的Activity类
     * @param bundle 跳转所携带的信息
     */
    open fun startActivity(clz: Class<*>?, bundle: Bundle?) {
        val intent = Intent(this, clz)
        if (bundle != null) {
            intent.putExtras(bundle)
        }
        startActivity(intent)
    }

    open fun startActivityFinish(clz: Class<*>?) {
        startActivity(Intent(this, clz))
        finish()
    }

    open fun startActivityFinish(clz: Class<*>?, bundle: Bundle?) {
        val intent = Intent(this, clz)
        if (bundle != null) {
            intent.putExtras(bundle)
        }
        startActivity(intent)
        finish()
    }

    open fun startActivityFinish(clz: Class<*>?, bundle: Bundle?, flag: Int) {
        val intent = Intent(this, clz)
        intent.flags = flag
        if (bundle != null) {
            intent.putExtras(bundle)
        }
        startActivity(intent)
        finish()
    }

    /**
     * 跳转容器页面
     * @param canonicalName 规范名 : Fragment.class.getCanonicalName()
     */
    open fun startContainerActivity(canonicalName: String?) {
        startContainerActivity(canonicalName, null)
    }

    /**
     * 跳转容器页面
     * @param canonicalName 规范名 : Fragment.class.getCanonicalName()
     * @param bundle        跳转所携带的信息
     */
    open fun startContainerActivity(canonicalName: String?, bundle: Bundle?) {
        val intent = Intent(this, ContainerActivity::class.java)
        intent.putExtra(ContainerActivity.FRAGMENT, canonicalName)
        if (bundle != null) {
            intent.putExtra(ContainerActivity.BUNDLE, bundle)
        }
        startActivity(intent)
    }


}